//System header files
#include "stdio.h"
#include "string.h"
#include "pthread.h"
#include "unistd.h"

//C project header files
#include "Dual_Link_List.h"
#include "thread_routine.h"
#include "alarm_data_mutex.h"
#include "alarm_thread.h"
#include "datapool_mutex.h"
#include "threads.h"
#include "insert_alarm.h"
#include "tcp_funs.h"
#include "udp_funs.h"

//Testing header files
#include "CreateLinkListHelper.h"
#include "PrintDataHelper.h"

void test_dual_link_list();
void test_multithread();
void test_alarm_thread();
void test_list_process_threads();
void test_tcp_server();
void test_tcp_client();
void test_udp_client();

#define MAX_CLIENT_COUNT 200

//Main testing entry
int main()
{
	//test_dual_link_list();
	//test_multithread();
	//test_alarm_thread();
	//test_list_process_threads();
	//test_tcp_server();
	test_tcp_client();
	//test_udp_client();
	return 0;
}

void test_dual_link_list()
{
	//p_ListNode list = create_link_list("ListConfiguration.txt");
	p_ListNode list = create_link_list_with_INT8_Node("TestProject/Test_data/int_case.txt");
	if(!list) {
		printf("fail to create Link List!\n");
		exit(1);
	}
	print_list(list,print_INT8);
	printf("The length of the link list is %d\n",get_length(list));

	int8_t insert_data = 2;
	if(insert_node(list,0,(void*)(insert_data)) == -1) {
		printf("fail to insert new node\n");
		printf("Program exit!\n");
		exit(1);
	}
	print_list(list,print_INT8);
	printf("The length of the link list is %d\n",get_length(list));	
	
	//char* data = (char*)malloc(sizeof(char));
	int8_t* data = (int8_t*)malloc(sizeof(int8_t));
	if(delete_node_by_index(list,0,(void*)data) == -1) {
		printf("Fail to delete the node\n");	
		printf("Program exit!\n");
		exit(1);
	}
	printf("Node %d has been deleted from the list\n",*data);
	print_list(list,print_INT8);
	printf("The length of the link list is %d\n",get_length(list));	

	destroy_link_list(list);
}

void test_multithread()
{
	pthread_t thread_id;
	void* thread_result;
	int status;

	char* p_str = "Moible+";
	status = pthread_create(
			&thread_id, NULL, thread_routine, (void*)p_str);
	if(status != 0) {
		printf("Fail to create pthread!\n");
		exit(1);
	}

	status = pthread_join(thread_id, &thread_result);
	if(status != 0) {
		printf("Fail to join pthread: %d\n", thread_id);
		exit(1);
	}
	/*if(thread_result == NULL) {
		return 0;
	}
	else {
		return 1;
	}*/
	printf("The result of subthread is %s\n", (char*)thread_result);

	return NULL;
}


void test_alarm_thread() 
{
	int status;
	char buffer[128];
	alarm_t* p_alarm = NULL;
/*	alarm_t** prior;
	alarm_t* next;*/

	//create a new alarm thread to process alarms
	pthread_t thread;
	status = pthread_create(&thread, NULL, alarm_thread, NULL);
	if(status !=0) {
		printf("Fail to create an alarm thread\n");
		exit(0);
	}

	//insert new alarms into alarm list from standard input by user
	while(1) {
		//allocate memory for a new alarm node
		p_alarm = (alarm_t*)malloc(sizeof(alarm_t));
		if(!p_alarm) {
			printf("Fail to allocate memory for a new alarm list node.\n");
			exit(0);
		}

		//get alarm information from file to a single char buffer
		printf("Enter a alarm information, include seconds and message.\n");
		if( fgets(buffer,sizeof(buffer),stdin) == NULL ) {
			printf("Fail to read seconds and message of alarm from command line.\n");
			exit(0);
		}
		if(strlen(buffer) <= 1) {
			printf("The alarm information has not been completed, plz continue inputting...\n");
			continue;
		}
		//set alarm time, seconds and message from buffer
		/*if( sscanf(buffer, "%d %64[^\n]", &(p_alarm->seconds), p_alarm->message) < 2 ) {
			printf("Fail to read buffer to new alarm node.\n");
			exit(0);
		}*/
		if( sscanf(buffer, "%d %64[^\n]s", &(p_alarm->seconds), p_alarm->message) < 2 ) {
					printf("Fail to read buffer to new alarm node.\n");
					exit(0);
		}

		p_alarm->time = p_alarm->seconds + time(NULL);

		//lock alarm list using alarm_mutex
		pthread_mutex_lock(&alarm_mutex);
		if(status != 0) {
			printf("Fail to lock alarm mutex in main thread.\n");
			exit(0);
		}

		insert_alarm(p_alarm);

/*
		//insert the new alarm into the alarm list
		prior = &alarm_list; 
		next = *prior;
		while(next != NULL) {
			if(p_alarm->seconds <= next->seconds) {
				p_alarm->next = next;
				*prior = p_alarm;
			}
			next = next->next;
			prior =&((*prior)->next);
		}
		if(next == NULL) {
			*prior = p_alarm;
			p_alarm->next = NULL;
		}

#ifdef DEBUG
		//print alarm list
		next = alarm_list;
		int16_t count = 0;
		printf("The current alarm list is:\n");
		while(next != NULL) {
			count++;
			printf("alarm%d seconds:%d message:%s", count, next->seconds, next->message);
			next = next->next;
		}
		printf("\n");
#endif
*/

		//unlock alarm list using alarm_mutex
		status = pthread_mutex_unlock(&alarm_mutex);
		if(status != 0) {
			printf("Fail to unlock alarm mutex in main thread.\n");
			exit(0);
		}
	} //end of while
}

void test_list_process_threads()
{
	pthread_t read_thread, process_thread, write_thread;
	int ret_val;

	printf("Main function started.\n");

	p_list = create_node(NULL);
	if(NULL == p_list) {
		printf("Fail to create header pointer to data pool, "
				"program exit.\n");
		exit(0);
	}

	ret_val = pthread_create(&read_thread, NULL, data_read_thread, (void*)sizeof(int));
	if(0 != ret_val) {
		printf("Fail to create data read thread, "
				"main function exit.\n");
		exit(0);
	}

	ret_val = pthread_create(&process_thread, NULL, data_process_thread, NULL);
	if(0 != ret_val) {
		printf("Fail to create data process thread, "
				"main function exit.\n");
		exit(0);
	}

	ret_val = pthread_create(&write_thread, NULL, data_write_thread, NULL);
	if(0 != ret_val) {
		printf("Fail to create data write thread, "
				"main function exit.\n");
		exit(0);
	}

	pthread_exit(NULL);

	return;
}

void test_tcp_server()
{
	tcp_server();
}

void test_tcp_client()
{
	int client_count;
	pid_t pid;

	for(client_count = 0; client_count < MAX_CLIENT_COUNT; client_count++) {
		if( 0 == (pid = fork()) ) {
			tcp_client();
			printf("&test.c %d: client exit normally.\n", (int)getpid());
			exit(0);
		}
		printf("&test.c %d: fork a new tcp client.\n", (int)getpid());
	}

	//tcp_client();

	return;
}

void test_udp_client()
{
	udp_client();
}
